(function (global, noGlobal) {

    class StickyNote {
        constructor(options) {
            this.init(options);
        }

        init(options) {
            Object.assign(this, config, options);
            this.id = this.id ? this.id : new Date().getTime();
            StickyNote.top = Math.max(StickyNote.top, this.layer);
            if (!this.root) {
                this.root = document.body;
            }
            this.container = document.createElement('div');
            this.container.classList.add(this.className || 'note-container');
            this.root.appendChild(this.container);
            this.render();
            this.bindEvent();
        }

        save() {
            this.content = this.noteContent.innerHTML;
            store.set(this.id, {
                content: this.content || '',
                postTime: new Date().getTime(),
                x: this.x,
                y: this.y,
                layer: this.layer
            });
        }

        close() {
            if (this.root) {
                this.root.removeChild(this.container);
            }
        }

        bindEvent() {
            var pos = {}, self = this, canMove = false;
            addEvent(this.titleBar, 'mousedown', function (e) {
                pos.x = e.clientX - self.container.offsetLeft;
                pos.y = e.clientY - self.container.offsetTop;
                if (e.button == 0) {
                    canMove = true;
                }
            });
            addEvent(document, 'mousemove', function (e) {
                if (!canMove) return;
                var
                    x = Math.min(document.documentElement.clientWidth - self.width, Math.max(e.clientX - pos.x, 0)),
                    y = Math.min(document.documentElement.clientHeight - self.height, Math.max(e.clientY - pos.y, 0));

                self.container.style.left = x + 'px';
                self.container.style.top = y + 'px';
            });
            addEvent(document, 'mouseup', function (e) {
                canMove = false;
            });

            addEvent(self.noteContent, 'keyup', function (e) {
                self.save();
            });

            addEvent(self.btnClose, 'click', function (e) {
                self.close();
                self.save();
            })

            addEvent(self.btnNew, 'click', function (e) {
                var x = self.x,
                    y = self.y,
                    maxWidth = document.documentElement.clientWidth - self.width,
                    maxHeight = document.documentElement.clientHeight - self.height;
                if (x >= maxWidth || x < 0) {
                    vx *= -1;
                }

                if (y >= maxHeight || y < 0) {
                    vy *= -1;
                }

                x = x + 20 * vx;
                y = y + 20 * vy;

                new StickyNote({
                    root: self.root,
                    x: x,
                    y: y,
                    layer: StickyNote.top++
                });
            });
            addEvent(self.btnRemove, 'click', function (e) {
                store.remove(self.id);
                self.close();
            })

            addEvent(self.container, 'mousedown', function (e) {
                if (e.button != 0) return;
                self.layer = StickyNote.top++;
                self.container.style.zIndex = self.layer;
            });

            addEvent(self.container, 'mouseup', function (e) {
                self.x = self.container.offsetLeft || 0;
                self.y = self.container.offsetTop || 0;
                self.save();
            });
        }

        render() {
            var self = this;
            self.container.innerHTML = template.replace(/\{\{([^\}]+)\}\}/g, ($0, $1) => self[$1]);
            self.titleBar = self.container.querySelector('.note-title');
            self.noteContent = self.container.querySelector('.note-content');
            self.btnClose = self.container.querySelector('.btn-close');
            self.btnNew = self.container.querySelector('.btn-new');
            self.btnRemove = self.container.querySelector('.btn-remove');
            self.container.style.position = 'absolute';
            self.container.style.left = self.x + 'px';
            self.container.style.top = self.y + 'px';
            self.noteContent.innerHTML = self.content;
            self.container.data = self;
            self.container.style.zIndex = self.layer;
            self.save();
        }
    }

    StickyNote.top = 0;
    var vx = 1, vy = 1;
    const config = {
        id: null,
        root: null,
        title: '便笺',
        btnCloseTip: '关闭',
        textBtnNew: '新建笔记',
        textBtnRemove: '删除笔记',
        container: null,
        titleBar: null,
        width: 300,
        height: 400,
        x: 0,
        y: 0,
        layer: 0,
        content: '',
    };


    const template = [
        '<div class="note-title">',
        '   <h6>{{title}}</h6>',
        '   <a href="javascript:;" title="{{btnCloseTip}}" class="btn-close">&times;</a>',
        '</div>',
        '<div class="note-content" contenteditable="true"></div>',
        '<div class="note-footer">',
        '   <button class="btn-new">{{textBtnNew}}</button>',
        '   <button class="btn-remove">{{textBtnRemove}}</button>',
        '</div>'
    ].join('\n');

    function addEvent(el, type, fn) {
        var ieType = 'on' + type;
        if ('addEventListener' in window) {
            addEventListener.call(el, type, fn, false);
        } else if ('attachEvent' in el) {
            attachEvent.call(el, ieType, fn, false);
        } else {
            el[ieType] = fn;
        }
    }

    function removeEvent(el, type, fn) {
        var ieType = 'on' + type;
        if ('removeEventListener' in window) {
            removeEventListener.call(el, type, fn, false);
        } else if ('dispatchEvent' in el) {
            el.dispatch(ieType, fn);
        } else {
            el[ieType] = null;
        }
    }

    const store = {
        appId: 'stickyNote',
        data: {},
        get(id) {
            return store.data ? store.data[id] : {};
        },

        set(id, value) {
            store.data[id] = value;
        },

        remove(id) {
            delete store.data[id];
        },

        setup() {
            try {
                store.data = JSON.parse(localStorage[store.appId]) || {};
            } catch (e) {
                store.data = {};
            }
            var data = store.data;
            if (!isEmpty(data)) {
                for (var k in data) {
                    new StickyNote({
                        root: document.body,
                        id: k,
                        x: data[k].x,
                        y: data[k].y,
                        layer: data[k].layer,
                        content: data[k].content
                    });
                }
            } else {
                new StickyNote({
                    root: document.body,
                    x: (document.documentElement.clientWidth - config.width) / 2,
                    y: (document.documentElement.clientHeight - config.height) / 2,
                });
            }
            window.onunload = function () {
                localStorage.setItem(store.appId, JSON.stringify(data));
            }
        },

        unsetup() {
            store.data = {};
            localStorage.removeItem(store.appId);
            window.onunload = null;
        }
    };

    function isEmpty(o) {
        if (typeof o === 'string' || Array.isArray(o)) {
            return o.length === 0;
        } else if (typeof o === 'object') {
            for (let k in o) {
                if (!o.hasOwnProperty(k)) continue;
                return false;
            }
            return true;
        } else {
            return o == null;
        }
    }

    var domReady = {
        tasks: [],
        isReady: false,
        ready: function (fn) {
            domReady.tasks.push(fn);
            if (domReady.isReady) {
                return domReady.completed();
            } else {
                addEvent(document, 'DOMContentLoaded', domReady.completed);
                addEvent(document, 'readystatechange', function () {
                    if (/^(?:interactive|complete)$/.test(document.readyState)) {
                        domReady.completed();
                        removeEvent(document, 'readystatechange', arguments.callee);
                    }
                });
            }
        },
        completed: function () {
            removeEvent(document, 'DOMContentLoaded', domReady.completed);
            domReady.isReady = true;
            domReady.execTasks();
        },
        execTasks: function () {
            while (domReady.tasks.length) {
                domReady.tasks.shift()();
            }
            ;
        }
    }

    domReady.ready(store.setup);

    window.store = store;
})();
